package com.uinnova.product.eam.web.eam.mvc;

import com.alibaba.fastjson.JSONObject;
import com.binary.core.io.Resource;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.exception.ServiceException;
import com.binary.framework.util.ControllerUtils;
import com.binary.framework.web.RemoteResult;
import com.binary.jdbc.Page;
import com.binary.json.JSON;
import com.google.common.collect.Sets;
import com.uinnova.product.eam.comm.exception.BusinessException;
import com.uinnova.product.eam.model.CiUpAndDownCdt;
import com.uinnova.product.eam.model.DataModuleRltClassDto;
import com.uinnova.product.eam.model.RltInfoQueryVo;
import com.uinnova.product.eam.model.VcCiRltInfo;
import com.uinnova.product.eam.model.asset.EamCiRltDTO;
import com.uinnova.product.eam.model.vo.ESRltSearchBeanVO;
import com.uinnova.product.eam.service.ICIRltSwitchSvc;
import com.uinnova.product.eam.service.ICISwitchSvc;
import com.uinnova.product.eam.web.diagram.bean.CiRltCdt;
import com.uinnova.product.eam.web.eam.peer.IExportPeer;
import com.uinnova.product.vmdb.comm.doc.annotation.ModDesc;
import com.uinnova.product.vmdb.comm.model.ci.CcCiClass;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.rlt.bean.CcCiRltInfo;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.ESCIRltInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.business.*;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.bean.cmdb.query.ESRltSearchBean;
import com.uino.bean.permission.base.SysUser;
import com.uino.util.sys.SysUtil;
import io.micrometer.core.instrument.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

@RestController
@RequestMapping(value = "/eam/ciRlt")
public class EamCiRltMvc {

    @Autowired
    private ICIRltSwitchSvc ciRltApiSvc;

    @javax.annotation.Resource
    private IExportPeer exportPeer;

    @Autowired
    private ICISwitchSvc iciSwitchSvc;

    @PostMapping("bindCiRlt")
    @ModDesc(desc = "保存关系数据", pDesc = "关系数据传输对象", pType = BindCiRltRequestDto.class, rDesc = "操作是否成功", rType = Boolean.class)
    public RemoteResult bindCiRlt(@RequestParam(defaultValue = "BASELINE") LibType libType, @RequestBody BindCiRltRequestDto dto) {
        Long rltId = ciRltApiSvc.bindCiRlt(dto, libType);
        Object result = "";
        if (!BinaryUtils.isEmpty(rltId) && rltId > 0) {
            List<CcCiRltInfo> rltList = ciRltApiSvc.searchRltByIds(Sets.newHashSet(rltId), libType);
            if (!CollectionUtils.isEmpty(rltList)) {
                result = rltList.get(0);
            }
        }
        return new RemoteResult(result);
    }

    @PostMapping("bindCiRltBatch")
    @ModDesc(desc = "批量绑定关系数据", pDesc = "关系数据传输对象", pType = BindCiRltRequestDto.class, rDesc = "操作是否成功", rType = Boolean.class)
    public void bindCiRltBatch(@RequestParam(defaultValue = "PRIVATE") LibType libType, @RequestBody List<BindCiRltRequestDto> reqBean,
                               HttpServletRequest request, HttpServletResponse response) {
        List<ESCIRltInfo> rltInfos = ciRltApiSvc.bindCiRltBatch(reqBean, libType);
        if (BinaryUtils.isEmpty(rltInfos)) {
            ControllerUtils.returnJson(request, response, "");
        } else {
            ControllerUtils.returnJson(request, response, rltInfos);
        }
    }

    /**
     * 根据ciId解除ci关系（无论是目标还是源都解除）
     *
     * @param ciId 源/目标ciId
     * @return
     */
    @PostMapping("delRltByCiId")
    @ModDesc(desc = "根据对象id清楚相关关系数据(无论是目标还是源都解除)", pDesc = "对象id", pType = Long.class, rDesc = "操作是否成功", rType = Boolean.class)
    public void delRltByCiId(@RequestParam(defaultValue = "BASELINE") LibType libType,
                             @RequestBody Long ciId, HttpServletRequest request, HttpServletResponse response) {
        ciRltApiSvc.delRltByCiId(ciId, libType);
        ControllerUtils.returnJson(request, response, true);
    }

    /**
     * 修改ci关系属性
     *
     * @param reqBean
     * @param request
     * @param response
     */
    @PostMapping("updateCiRltAttr")
    @ModDesc(desc = "更改关系属性", pDesc = "要修改的关系属性", pType = UpdateCiRltRequestDto.class, rDesc = "操作是否成功", rType = Boolean.class)
    public void updateCiRltAttr(@RequestParam(defaultValue = "BASELINE") LibType libType,
                                @RequestBody UpdateCiRltRequestDto reqBean, HttpServletRequest request,
                                HttpServletResponse response) {
        ciRltApiSvc.updateCiRltAttr(reqBean.getCiRltId(), reqBean.getAttrs(), libType);
        ControllerUtils.returnJson(request, response, true);
    }

    /**
     * 查询ci关系-根据查询bean
     *
     * @param reqBean
     * @param request
     * @param response
     */
    @PostMapping("searchRltByBean")
    @ModDesc(desc = "条件查询关系数据", pDesc = "查询条件", pType = ESRltSearchBean.class, rDesc = "关系数据分页结果", rType = Page.class, rcType = CcCiRltInfo.class)
    public void searchRltByBean(@RequestParam(defaultValue = "BASELINE") LibType libType,
                                @RequestBody ESRltSearchBeanVO reqBean, HttpServletRequest request,
                                HttpServletResponse response) {
        isConvertibleToLong(reqBean);
        Page<CcCiRltInfo> results = ciRltApiSvc.searchRltByBeanVO(reqBean, libType);
        ControllerUtils.returnJson(request, response, results);
    }

    private void isConvertibleToLong(ESRltSearchBeanVO esRltSearchBeanVO) {
        if (StringUtils.isNotBlank(esRltSearchBeanVO.getGteTime())) {
            String gteTime = esRltSearchBeanVO.getGteTime().replace("/", "");
            try {
                Long.parseLong(gteTime);
            } catch (NumberFormatException e) {
                throw new BusinessException("时间区间查询 大于等于传参有问题请核实在传入");
            }
        }
        if (StringUtils.isNotBlank(esRltSearchBeanVO.getLteTime())) {
            String lteTime = esRltSearchBeanVO.getLteTime().replace("/", "");
            try {
                Long.parseLong(lteTime);
            } catch (NumberFormatException e) {
                throw new BusinessException("时间区间查询 大于等于传参有问题请核实在传入");
            }
        }
        if (StringUtils.isNotBlank(esRltSearchBeanVO.getGteTime()) && StringUtils.isNotBlank(esRltSearchBeanVO.getLteTime())) {
            String gteTime = esRltSearchBeanVO.getGteTime().replace("/", "");
            String lteTime = esRltSearchBeanVO.getLteTime().replace("/", "");
            if (Long.parseLong(gteTime) > Long.parseLong(lteTime)) {
                throw new BusinessException("时间区间查询 起始时间不能大于终止时间");
            }
        }
    }

    /**
     * 关系用户列表
     * @param reqBean
     * @return
     */
    @PostMapping("/findCiRltUserList")
    @ResponseBody
    public RemoteResult findCiRltUserList(@RequestBody ESRltSearchBean reqBean) {
        List<SysUser> ciRltUsers = ciRltApiSvc.findCiRltUserList(reqBean);
        return new RemoteResult(ciRltUsers);
    }

    /**
     * 查询ci关系-根据ids
     *
     * @param body     查询条件
     * @param request
     * @param response
     */
    @PostMapping("searchRltByIds")
    @ModDesc(desc = "条件查询关系数据", pDesc = "查询条件", pType = ESRltSearchBean.class, rDesc = "关系数据分页结果", rType = Page.class, rcType = CcCiRltInfo.class)
    public void searchRltByIds(@RequestParam(defaultValue = "BASELINE") LibType libType,
                               @RequestBody String body, HttpServletRequest request,
                               HttpServletResponse response) {
        CiRltCdt cdt = JSON.toObject(body, CiRltCdt.class);
        Long[] ciIds = cdt.getIds();
        HashSet<Long> longs = new HashSet<>(Arrays.asList(ciIds));
        List<CcCiRltInfo> ccCiRltInfos = ciRltApiSvc.searchRltByIds(longs, libType);
        ControllerUtils.returnJson(request, response, ccCiRltInfos);
    }

    /**
     * 查询ci关系-根据ciCodes
     *
     * @param reqBean  查询条件
     * @param request
     * @param response
     */
    @PostMapping("searchRltByRltCodes")
    @ModDesc(desc = "条件查询关系数据", pDesc = "查询条件", pType = ESRltSearchBean.class, rDesc = "关系数据结果", rType = Page.class, rcType = CcCiRltInfo.class)
    public void searchRltByRltCodes(@RequestParam(defaultValue = "BASELINE") LibType libType, @RequestBody ESRltSearchBean reqBean,
                                    HttpServletRequest request, HttpServletResponse response) {
        List<EamCiRltDTO> ccCiRltInfos = ciRltApiSvc.searchRltByRltCodes(reqBean, libType);
        ControllerUtils.returnJson(request, response, ccCiRltInfos);
    }

    /**
     * 查询ci关系-根据rltUniqueCodes
     *
     * @param rltInfoQueryVo  查询条件
     * @param request
     * @param response
     */
    @PostMapping("searchRltByRltUniqueCodes/withoutCi")
    @ModDesc(desc = "条件查询关系数据", pDesc = "查询条件", pType = ESRltSearchBean.class, rDesc = "关系数据结果", rType = Page.class, rcType = CcCiRltInfo.class)
    public void searchRltByRltCodes1(@RequestBody RltInfoQueryVo rltInfoQueryVo,
                                    HttpServletRequest request, HttpServletResponse response) {
        List<CcCiRltInfo> ccCiRltInfos = ciRltApiSvc.searchRltByRltUniqueCodesWithoutCi(rltInfoQueryVo);
        ControllerUtils.returnJson(request, response, ccCiRltInfos);
    }

    /**
     * 清除指定分类下所有ci关系
     *
     * @param rltClassId
     * @param request
     * @param response
     */
    @PostMapping("clearRltByClassId")
    @ModDesc(desc = "清除指定分类下关系数据", pDesc = "关系分类id", pType = Long.class, rDesc = "操作是否成功", rType = Boolean.class)
    public void clearRltByClassId(@RequestParam(defaultValue = "BASELINE") LibType libType,
                                  @RequestBody Long rltClassId, HttpServletRequest request,
                                  HttpServletResponse response) {
        ciRltApiSvc.clearRltByClassId(rltClassId, libType);
        ControllerUtils.returnJson(request, response, true);
    }

    /**
     * 清除指定分类下,当前用户的所有ci关系
     *
     * @param body
     * @param request
     * @param response
     */
    @PostMapping("clearUserRltByClassId")
    @ModDesc(desc = "清除当前用户指定分类下关系数据", pDesc = "关系分类id", pType = Long.class, rDesc = "操作是否成功", rType = Boolean.class)
    public void clearUserRltByClassId(
            @RequestParam(defaultValue = "BASELINE") LibType libType,
            @RequestBody String body, HttpServletRequest request, HttpServletResponse response) {
        JSONObject json = JSONObject.parseObject(body);
        Long rltClassId;
        if (json.containsKey("rltClassId")) {
            rltClassId = json.getLong("rltClassId");
        } else {
            throw new ServiceException("rltClassId不能为空");
        }
        String ownerCode = null;
        if (json.containsKey("ownerCode")) {
            ownerCode = json.getString("ownerCode");

        }
        ciRltApiSvc.clearUserRltByClassId(rltClassId,ownerCode,libType);
        ControllerUtils.returnJson(request, response, true);
    }


    /**
     * 导出ci关系
     *
     * @param rltClassIds
     * @param request
     * @param response
     */
    @PostMapping("exportCiRlt")
    @ModDesc(desc = "导出关系数据(exportData:是否导出数据1=是，0=否;rltClassIds:关系分类id集合)", pDesc = "关系分类id集合", pType = Set.class, pcType = Long.class, rDesc = "关系数据文件", rType = Resource.class)
    public void exportCiRlt(@RequestParam(defaultValue = "DESIGN") LibType libType,
                            @RequestBody(required = false) Set<Long> rltClassIds,
                            @RequestParam(required = false) Boolean exportData,
                            @RequestParam(required = false) Boolean hasClsDef,
                            @RequestParam(required = false) String ownerCode,
                            HttpServletRequest request, HttpServletResponse response) {
        Resource file = ciRltApiSvc.exportCiRlt(rltClassIds, libType, ownerCode);
        ControllerUtils.returnResource(request, response, file);
    }

    /**
     * 导出ci关系
     *
     * @param rltClassIds
     * @param request
     * @param response
     */
    @GetMapping("exportCiRlt")
    @ModDesc(desc = "导出关系数据get请求(exportData:是否导出数据1=是，0=否;rltClassIds:关系分类id集合)", pDesc = "?exportData=1&rltClassIds=1,2", pType = String.class, rDesc = "关系数据文件", rType = Resource.class)
    public void exportCiRltGet(@RequestParam(defaultValue = "DESIGN") LibType libType,
                               @RequestParam(required = false) Set<Long> rltClassIds,
                               @RequestParam(required = false) Boolean exportData,
                               @RequestParam(required = false) String ownerCode,
                               HttpServletRequest request, HttpServletResponse response) {
        Resource file = ciRltApiSvc.exportCiRlt(rltClassIds, libType,ownerCode);
        ControllerUtils.returnResource(request, response, file);
    }

    /**
     * 导入ci关系
     *
     * @param file
     * @param request
     * @param response
     */
    @RequestMapping("importCiRlt")
    @ModDesc(desc = "一键导入关系数据", pDesc = "导入文件及要导入的关系分类信息", rDesc = "导入明细", rType = ImportSheetMessage.class)
    public void importCiRlt(@RequestParam(defaultValue = "DESIGN") LibType libType,
                            @RequestBody RltExcelInfoDto rltExcelInfoDto,
                            @RequestParam(required = false, value = "file") MultipartFile file, HttpServletRequest request,
                            HttpServletResponse response) {
        ImportResultMessage result = ciRltApiSvc.importCiRlt(rltExcelInfoDto.getExcelFilePath(), file, rltExcelInfoDto.getRltClsCodes(), libType);
        ControllerUtils.returnJson(request, response, result);
    }

    /**
     * 根据【关系ids OR 关系codes】解除ci关系
     *
     * @param reqDto
     * @param request
     * @param response
     */
    @PostMapping("delRltByIdsOrRltCodes")
    @ModDesc(desc = "根据关系ids或codes解除关系", pDesc = "解除关系请求传输对象", pType = DelRltReqDto.class, rDesc = "操作是否成功,1=成功，0=失败", rType = Integer.class)
    public void delRltByIdsOrRltCodes(@RequestParam(defaultValue = "BASELINE") LibType libType,
                                      @RequestBody DelRltReqDto reqDto, HttpServletRequest request,
                                      HttpServletResponse response) {
        Integer re = ciRltApiSvc.delRltByIdsOrRltCodes(reqDto.getRltIds(), reqDto.getRltCodes(), reqDto.getOwnerCode(), libType);
        ControllerUtils.returnJson(request, response, re);
    }

    /**
     * 解析关系excel
     *
     * @param excelFilePath
     * @param excelFile
     * @param request
     * @param response
     */
    @RequestMapping("parseRltExcel")
    @ModDesc(desc = "一键导入解析文件", pDesc = "关系Excel文件或文件路径", rDesc = "Excel解析结果", rType = ImportExcelMessage.class)
    public void parseRltExcel(@RequestParam(defaultValue = "DESIGN") LibType libType,
                              @RequestParam(required = false, value = "excelFilePath") String excelFilePath,
                              @RequestParam(value = "file", required = false) MultipartFile excelFile, HttpServletRequest request,
                              HttpServletResponse response) {
        ImportExcelMessage res = ciRltApiSvc.parseRltExcel(excelFilePath, excelFile, libType);
        ControllerUtils.returnJson(request, response, res);
    }

    @PostMapping("queryClassRltList")
    @ModDesc(desc = "查询CI分类之间的关系信息", pDesc = "查询条件", rDesc = "关系分类列表", rType = List.class)
    public void queryClassRltList(@RequestParam(defaultValue = "BASELINE") LibType libType,
                                  @RequestBody String body, HttpServletRequest request, HttpServletResponse response) {
        CiRltCdt cdt = JSON.toObject(body, CiRltCdt.class);
        // ci分类的ID
        Long[] ciClassIds = cdt.getIds();
        HashSet<Long> ciClassIdSet = new HashSet<>(Arrays.asList(ciClassIds));
        List<DataModuleRltClassDto> ccCiRltInfos = ciRltApiSvc.getClassRltList(ciClassIdSet, new HashSet<>(), libType);
        ControllerUtils.returnJson(request, response, ccCiRltInfos);
    }

    /**
     * 查询ci上下层的关系
     *
     * @param request
     * @param response
     * @param body
     */
    @PostMapping("/queryUpAndDownRlt")
    @ModDesc(desc = "查询层级关系信息", pDesc = "查询参数", pType = CiUpAndDownCdt.class, rDesc = "关系信息", rType = List.class, rcType = VcCiRltInfo.class)
    public void queryUpAndDownRlt(@RequestParam(defaultValue = "BASELINE") LibType libType,
                                  @RequestParam(required = false) boolean isCache,
                                  HttpServletRequest request, HttpServletResponse response,
                                  @RequestBody String body) {
        CiUpAndDownCdt cdt = JSON.toObject(body, CiUpAndDownCdt.class);
        if(cdt.getsCiId() == null){
            Assert.notNull(cdt.getCiCode(),"ciCode不能为空");
            ESCISearchBean esciSearchBean = new ESCISearchBean();
            esciSearchBean.setCiCodes(Collections.singletonList(cdt.getCiCode()));
            if(LibType.PRIVATE==libType){
                esciSearchBean.setOwnerCode(SysUtil.getCurrentUserInfo().getLoginCode());
            }
            Page<ESCIInfo> esciInfoPage = iciSwitchSvc.getCiSvc(libType).searchESCIByBean(esciSearchBean);
            if(!CollectionUtils.isEmpty(esciInfoPage.getData())){
                cdt.setsCiId(esciInfoPage.getData().get(0).getId());
            }
        }
        List<VcCiRltInfo> result = ciRltApiSvc.queryUpAndDownRlt(libType, cdt.getsCiId(), cdt.getCiClassIds(), cdt.getRltClassIds(), cdt.getUp(), cdt.getDown(), isCache);
        ControllerUtils.returnJson(request, response, result);
    }

    @GetMapping("/exportRltByDiagramId")
    @ModDesc(desc = "导出当前视图中关系数据", pDesc = "?diagramId=1", pType = Long.class, rDesc = "当前视图中关系数据", rType = String.class)
    public void exportRltByDiagramId(@RequestParam(defaultValue = "BASELINE") LibType libType,
                                     HttpServletRequest request, HttpServletResponse response,
                                     @RequestParam(name = "diagramId") Long diagramId) throws IOException {
        Resource file = exportPeer.exportRltByDiagramId(diagramId, libType);
        ControllerUtils.returnResource(request, response, file);
    }

    /**
     * 获取所有关系分类
     *
     * @param request
     * @param response
     */
    @PostMapping("/queryAllClasses")
    @ModDesc(desc = "查询所有关系分类", pDesc = "无", rDesc = "关系分类列表", rType = List.class, rcType = CcCiClassInfo.class)
    public void queryAllClasses(HttpServletRequest request, HttpServletResponse response,
                                @RequestBody JSONObject jsonObject) {
        LibType libType = jsonObject.getObject("libType", LibType.class);
        List<CcCiClassInfo> results = ciRltApiSvc.queryAllClasses(libType);
        ControllerUtils.returnJson(request, response, results);
    }

    @RequestMapping("/queryCiBetweenRlt")
    @ModDesc(desc="通过对象CiCde查询对象间的关系",pDesc="对象ciCode",pType=String.class,rDesc="关系信息,包含相关的CI信息",rType=CcCiRltInfo.class)
    public void queryCiBetweenRlt(HttpServletRequest request, HttpServletResponse response, @RequestBody String body) {
        JSONObject json = JSONObject.parseObject(body);
        List<String> ciCodes = JSONObject.parseArray(json.get("ciCodes").toString(), String.class);
        //查询关系信息
        List<CcCiRltInfo> result = ciRltApiSvc.queryCiBetWeenRlt(ciCodes);
        ControllerUtils.returnJson(request, response, result);
    }

    @RequestMapping("/getRltClassByCode")
    @ModDesc(desc="根据ciCode查询关系定义",pDesc="关系code",pType=String.class,rDesc="关系信息,包含相关的CI信息",rType=CcCiRltInfo.class)
    public void getRltClassByCode(HttpServletRequest request, HttpServletResponse response, @RequestBody String rltClassCode) {
        //查询关系信息
        CcCiClassInfo result = ciRltApiSvc.getRltClassByCode(rltClassCode);
        ControllerUtils.returnJson(request, response, result);
    }

    @PostMapping("/queryClassesByClassIds")
    @ModDesc(desc = "通过关系分类ids查关系分类列表", pDesc = "无", rDesc = "关系分类列表", rType = List.class, rcType = CcCiClassInfo.class)
    public void queryClassesByRltClassIds(HttpServletRequest request, HttpServletResponse response, @RequestBody List<Long> rltClassIds) {
        List<CcCiClassInfo> results = ciRltApiSvc.queryClassesByRltClassIds(rltClassIds);
        ControllerUtils.returnJson(request, response, results);
    }

    @PostMapping("/findNonCompliance")
    public void findNonCompliance(@RequestParam Long rltClassId,@RequestParam(defaultValue = "BASELINE") LibType libType,HttpServletRequest request,
                                  HttpServletResponse response) {
        boolean result = ciRltApiSvc.findNonCompliance(rltClassId,libType);
        ControllerUtils.returnJson(request, response, result);
    }

    @PostMapping("exportCiRltByConditions")
    public void exportCiRltByConditions(@RequestParam(defaultValue = "BASELINE") LibType libType,
                                        @RequestBody ESRltSearchBeanVO reqBean,
                                        @RequestParam(required = false) String ownerCode,
                                        HttpServletRequest request,
                                        HttpServletResponse response) {
        isConvertibleToLong(reqBean);
        Resource file = ciRltApiSvc.exportCiRltByConditions(reqBean, libType, ownerCode);
        ControllerUtils.returnResource(request, response, file);
    }

    @GetMapping(value = "/filterByVisualModel")
    @ModDesc(desc = "根据元模型过滤关系分类", pDesc = "对象分类id", pType = Long.class, rDesc = "分类信息", rType = Object.class)
    public RemoteResult filterByVisualModel(@RequestParam Long sourceClassId, @RequestParam(required = false) Long targetClassId) {
        List<CcCiClass> res = ciRltApiSvc.filterByVisualModel(sourceClassId, targetClassId);
        return new RemoteResult(res);
    }
}
